package msgpack

import (
	"bytes"
	"fmt"
	"io"
)

func writeLen(w io.Writer, l int) (n int, err error) {
	if l <= 0x7F {
		w.Write([]byte{byte(l) | 0x80})
		n++
	} else if l <= 0x3FFF {
		v := byte(l>>7) & 0x7F
		w.Write([]byte{v})

		v = byte(l) | 0x80
		w.Write([]byte{v})
		n += 2
	} else if l <= 0x1FFFFF {
		v := byte(l>>14) & 0x7F
		w.Write([]byte{v})

		v = byte(l>>7) & 0x7F
		w.Write([]byte{v})

		v = byte(l) | 0x80
		w.Write([]byte{v})
		n += 3
	} else if l <= 0xFFFFFFF {
		v := byte(l>>21) & 0x7F
		w.Write([]byte{v})

		v = byte(l>>14) & 0x7F
		w.Write([]byte{v})

		v = byte(l>>7) & 0x7F
		w.Write([]byte{v})

		v = byte(l) | 0x80
		w.Write([]byte{v})
		n += 4
	} else {
		return 0, fmt.Errorf("overrange %d", 0xFFFFFFF)
	}
	return
}

func readLen(r io.Reader, l *int) (n int, err error) {
	var buf [1]byte
	var n0 int
	for {
		n0, err = r.Read(buf[:])
		if n0 > 0 {
			n += n0
		}
		if err != nil {
			return
		}
		firstBit := buf[0] & 0x80
		*l = *l<<7 + int(buf[0]&0x7F)
		if firstBit != 0 {
			return
		}
	}
	return
}

// 打包
func PackHeadMsg(w io.Writer, head string, body []byte) (n int, err error) {
	headBuf := []byte(head)
	headL := len(headBuf)

	var n0 int
	n0, err = writeLen(w, headL)
	if n0 > 0 {
		n += n0
	}
	if err != nil {
		return
	}
	w.Write(headBuf)
	n += headL
	if len(body) > 0 {
		w.Write(body)
		n += len(body)
	}
	return
}

// 解包
func ExtractHeadMsg(buf []byte) (head string, body []byte, err error) {
	var n0, l int
	r := bytes.NewReader(buf)
	n0, err = readLen(r, &l)
	if err != nil {
		return
	}

	idx := n0
	if len(buf) < l+idx {
		err = fmt.Errorf("need more data")
		return
	}
	head = string(buf[idx : idx+l])
	idx += l
	body = buf[idx:]
	return
}
